// Copyright (c) 2022 Presto Labs Pte. Ltd.
// Author: qiang

#pragma once

#include <cstdio>
#include <map>
#include <memory>
#include <string>
#include <vector>

#include <rapidjson/document.h>

#include "coin2/exchange/base/order/order.h"

namespace coin2::exchange::bitget_futures::order_v1 {

class BitgetFuturesParser : public base::order::BaseParser {
 public:
  using CurrencyBalance = coin::proto::CurrencyBalance;
  using RawProductTypeBalanceMap = std::unordered_map<std::string, RawBalanceMap>;
  using RawProductTypePositionMap = std::unordered_map<std::string, RawPositionMap>;
  using ProductFillElement = coin::proto::ProductFillElement;

  const ParseResult& ParseRawMessage(const RawMessage& msg) override;
  AccountBalance ParseBalance(const JsonValue& doc) override;
  AccountPosition ParsePosition(const JsonValue& doc) override;
  bool ParseRawBalance(const JsonValue& doc, RawBalanceMap* raw_balance_map);
  bool ParseRawPosition(const JsonValue& doc, RawPositionMap* raw_position_map);

 private:
  void ParseRestAccountBalance();
  void ParseRestAccountPosition();
  void ParseRestOpenOrders();
  void ParseSubmitResponse();
  void ParseCancelResponse();
  void ParseRestAllOrders();
  void ParseRestOrderInfoList();
  void ParseAccountBills();
  void ParseWsMessage();
  void ParseRestFillInfoList();

  bool ParseWsBalance(const JsonValue& doc, AccountBalance* acc_balance);
  bool ParseRawBalanceFromWs(const JsonValue& doc, RawBalanceMap* raw_balance_map);
  bool ParseWsPosition(const JsonValue& doc, AccountPosition* acc_position);

  std::set<std::string>& GetProductTypes(){
    if (0 == product_type_set_.size()){
      for (const auto* product : symcache_->GetProducts()) {
        auto product_type = Split(product->order_native_symbol(), "_")[1];
        product_type_set_.emplace(product_type);
      }
    }
    return product_type_set_;
  }

  void InitBalanceFromCacheMap(AccountBalance& acc_balance);
  void InitPositionFromCacheMap(AccountPosition& acc_position);

  ProductFillElement ParseRestFillInfo(const JsonValue& data);
  ProductOrderElement ParseRestOrderInfo(const JsonValue& data);
  ProductFillBundle ParseWsFillInfoListV1(const JsonValue& order_data);
  ProductOrderBundle ParseWsOrderInfoListV1(const JsonValue& order_data);

 private:
  int64_t last_ws_balance_timestamp_{0};
  bool is_query_historical_orders_ = false;
  coin::proto::OrderEvent order_event_;
  RawProductTypeBalanceMap balance_cache_map_;
  RawProductTypePositionMap position_cache_map_;
  bool is_account_balance_initialized_ = false;
  bool is_account_position_initialized_ = false;
  std::set<std::string> product_type_set_;
};

}  // namespace coin2::exchange::bitget_futures::order_v1
